import { DialogPlugin, TableProps, TableRowData } from 'tdesign-vue-next';
import { onUnmounted, ref } from 'vue';

import { ActionBarItem } from '@/components/common-action-bar/index.vue';
import { t } from '@/locales';
import { mitter } from '@/utils/mitt';

export interface UseCommonOptions {
  // api对象
  API: Recordable;
  // 是否分页
  page?: boolean;
  // 格式化查询条件的钩子函数
  formatSearch?: Function;
  // 格式化列表数据的钩子函数
  formatItem?: Function;
}

/**
 * 弹出确认对话框。
 *
 * 该函数通过DialogPlugin创建一个确认对话框，对话框中包含确认和取消按钮。
 * 用户点击确认按钮时，会执行传入的onConfirm回调函数，点击取消按钮或关闭对话框时，
 * 会执行传入的onClose回调函数（如果提供了的话）。
 *
 * @param options 对话框的配置选项，可以覆盖默认配置，包括主题、标题等。
 * @param onConfirm 确认按钮点击时执行的回调函数。
 * @param onClose 取消按钮点击或关闭对话框时执行的回调函数（可选）。
 */
export const $confirm = (options: any, onConfirm: Function, onClose?: Function) => {
  // 使用DialogPlugin的confirm方法创建一个确认对话框
  const dialogPlugin = DialogPlugin.confirm({
    header: t('common.tip'), // 默认对话框标题
    ...options, // 合并传入的配置选项
    confirmBtn: {
      theme: 'danger',
      content: t('common.confirm'),
      loading: false, // 默认确认按钮不处于加载状态
    },
    cancelBtn: {
      content: t('common.cancel'),
    },
    async onConfirm() {
      // 点击确认按钮时，设置按钮为加载状态
      dialogPlugin.update({ confirmBtn: { loading: true } });
      try {
        await onConfirm(); // 执行传入的确认回调函数
        dialogPlugin.hide(); // 隐藏对话框
      } catch (error) {
        dialogPlugin.update({ confirmBtn: { loading: false } });
      }
    },
    onClose() {
      // 关闭对话框时，如果提供了onClose回调，则执行之
      if (onClose) {
        onClose();
      }
      dialogPlugin.hide(); // 隐藏对话框
    },
  });
};

export const isLoading = ref(false);
export const dialog = ref(null);
const paginationDefault = {
  current: 1,
  pageSize: 10,
  pageSizeOptions: [10, 20, 30, 50, 100, 200],
};

/**
 * 使用常见的表格、对话框等功能的钩子函数。
 *
 * @param {UseCommonOptions} options - 使用钩子函数时的配置选项，包括API对象和是否分页。
 * @param {Function} formatItem - 可选的格式化项函数，用于自定义数据项的显示。
 * @returns {Object} 返回包含表格操作、对话框操作和动作操作的对象。
 */
export const useCommon = (options: UseCommonOptions) => {
  const pagination = ref<TableProps['pagination']>({ ...paginationDefault });
  const list = ref<TableProps['data']>([]);
  const selectedRowKeys = ref<TableProps['selectedRowKeys']>([]);

  const { API } = options;
  const page = options.page === undefined ? true : options.page;

  pagination.value = page ? paginationDefault : null;

  // 初始化查询条件
  let condition = {};

  // 表格相关操作的对象
  const tableFn: Recordable = {
    /**
     * 异步获取列表数据。
     */
    async getList() {
      // 标记加载状态为true
      isLoading.value = true;

      let params = {};
      if (page) {
        // 获取当前页码和每页大小
        const { current, pageSize } = pagination.value;
        // 构建查询参数
        params = {
          page: current,
          limit: pageSize,
        };
      }

      // 调用API获取列表数据
      const res = await API.list(Object.assign(params, condition));

      // 根据是否分页，处理返回的数据
      const items = page ? res.items : res;

      // 如果当前页没有数据且页码大于1，回退一页并重新获取数据
      if (page) {
        if (!items.length && pagination.value.current > 1) {
          pagination.value.current -= 1;
          this.getList();
        }
      }

      // 格式化数据项，并更新列表数据
      list.value = items.map((v: Recordable) => {
        // 如果存在格式化项函数，调用之
        // eslint-disable-next-line no-unused-expressions
        options.formatItem && options.formatItem(v);

        return v;
      });

      // 如果是分页，更新总页数
      if (page) {
        pagination.value.total = res.meta.totalItems;
      }

      // 标记加载状态为false
      isLoading.value = false;
    },
    /**
     * 根据查询条件获取列表数据。
     * @param {any} data - 查询条件。
     */
    search(data: any) {
      selectedRowKeys.value = [];
      pagination.value.current = 1;
      condition = options.formatSearch ? options.formatSearch(data) : data;
      tableFn.getList();
    },
    /**
     * 重置查询条件，并获取列表数据。
     */
    reset() {
      condition = {};
      tableFn.getList();
    },
    /**
     * 处理行选中变化事件。
     * @param {TableProps['selectedRowKeys']} value - 选中行的键值。
     */
    onSelectChange(value: TableProps['selectedRowKeys']) {
      selectedRowKeys.value = value;
    },
    /**
     * 处理分页变化事件。
     */
    onPageChange(pageInfo: { current: number; pageSize: number }) {
      // 更新分页信息
      pagination.value.current = pageInfo.current;
      pagination.value.pageSize = pageInfo.pageSize;
      // 获取列表数据
      tableFn.getList();
    },
    /**
     * 异步处理行显示状态的改变。
     * @param {TableRowData} row - 行数据。
     * @param {any} e - 事件对象。
     */
    async display(row: TableRowData, e: any) {
      await API.display(row.id, e);
      mitter.emit(`displayed`, row);
    },
    /**
     * 异步打开编辑对话框，并加载行数据。
     * @param {TableRowData} row - 行数据。
     */
    async edit(row: TableRowData) {
      const res = await API.detail(row.id);
      dialog.value.dialogShow('edit', res);
    },
    /**
     * 异步删除一行数据。
     * @param {TableRowData} row - 行数据。
     */
    async delete(row: TableRowData) {
      // 弹出确认删除的对话框
      $confirm({ body: t('common.deleteConfirm') }, async () => {
        await API.del(row.id);
        tableFn.getList();
      });
    },
  };

  // 对话框相关操作的对象
  const dialogFn = {
    /**
     * 异步提交新增或编辑的数据。
     * @param {'add' | 'edit'} type - 操作类型，'add'为新增，'edit'为编辑。
     * @param {TableRowData} data - 提交的数据。
     */
    async confirm(type: 'add' | 'edit', data: TableRowData) {
      const method = type === 'add' ? 'add' : 'update';
      try {
        await API[method](data);
        dialog.value.dialogHide();
        tableFn.getList();
      } catch (error) {
        dialog.value.loadingClear();
      }
    },
  };

  // 动作相关操作的对象
  const actionFn = {
    /**
     * 打开新增对话框。
     */
    addShow() {
      dialog.value.dialogShow('add');
    },
    /**
     * 批量删除选中的行。
     * @param {ActionBarItem} item - 操作项配置。
     */
    listBatDel({ message }: ActionBarItem) {
      $confirm(
        { body: message },
        async () => {
          await API.delbat(selectedRowKeys.value);
          selectedRowKeys.value = [];
          tableFn.getList();
        },
        () => {
          selectedRowKeys.value = [];
        },
      );
    },
    listClear({ theme, message }: ActionBarItem) {
      $confirm(
        { theme, body: message },
        async () => {
          await API.clear();
          selectedRowKeys.value = [];
          tableFn.getList();
        },
        () => {
          selectedRowKeys.value = [];
        },
      );
    },
    /**
     * 批量禁用选中的行。
     * @param {ActionBarItem} item - 操作项配置。
     */
    listBatDisable({ theme, message }: ActionBarItem) {
      $confirm(
        { theme, body: message },
        async () => {
          await API.displayBat({ ids: selectedRowKeys.value, display: 0 });
          selectedRowKeys.value = [];
          tableFn.getList();
        },
        () => {
          selectedRowKeys.value = [];
        },
      );
    },
    /**
     * 批量启用选中的行。
     * @param {ActionBarItem} item - 操作项配置。
     */
    listBatEnable({ theme, message }: ActionBarItem) {
      $confirm(
        { theme, body: message },
        async () => {
          await API.displayBat({ ids: selectedRowKeys.value, display: 1 });
          selectedRowKeys.value = [];
          tableFn.getList();
        },
        () => {
          selectedRowKeys.value = [];
        },
      );
    },
  };

  // 组件卸载时，清除所有事件监听器
  onUnmounted(() => {
    mitter.all.clear();
  });

  // 返回相关的操作对象
  return {
    pagination,
    list,
    selectedRowKeys,
    tableFn,
    dialogFn,
    actionFn,
  };
};
